home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / vbcc / machines / amiga68k / libsrc / fd2lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-24  |  22.6 KB  |  813 lines

  1. /*  fd2lib  by Volker Barthelmann                         */
  2. /*  rework 09/96 by Johnny Teveßen <j.tevessen@line.org>  */
  3.  
  4. /*  "T:"s removed: Not very portable!
  5. */
  6.  
  7. #define NDEBUG
  8.  
  9. #ifdef _DCC
  10. #  define CTYPE_NEAR
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <stdarg.h>
  18.  
  19. const char VersTag[] = "\0$VER: fd2lib 1.3 (15.9.96)";  /* AmigaOS version string. Doesn't hurt... */
  20.  
  21. #define MAXLINELEN       1000
  22. #define BUFFEREDLEN     16384   /* 1024 is standard */
  23.  
  24. #define NUMREGS        16
  25.  
  26. static const char *regnames[NUMREGS] =
  27. {
  28.   "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
  29.   "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"
  30. };
  31.  
  32. enum
  33. {
  34.   A0=0, A1, A2, A3, A4, A5, A6, A7,
  35.   D0  , D1, D2, D3, D4, D5, D6, D7
  36. };
  37.  
  38. #define SMALLCODE        1
  39. #define SMALLDATA        2
  40. #define FASTCALL         4
  41. #define NEWNOTATE        8
  42. #define VARGSLOGIC      16
  43. #define DEBUG           32
  44.  
  45. #ifndef   TRUE
  46.    typedef short BOOL;
  47. #  define TRUE  1
  48. #  define FALSE 0
  49. #endif
  50.  
  51. #ifndef   NULL
  52. #  define NULL ((void *)0L)
  53. #endif
  54.  
  55. #ifdef __GNUC__
  56. #  define gnuspec(x) x
  57. #else
  58. #  define gnuspec(x)
  59. #endif
  60.  
  61. #define NORETURN gnuspec(__attribute__ ((noreturn)))
  62.  
  63. static const char *varargs[] =
  64. {
  65. #include "vargs.h"
  66.   NULL, NULL
  67. };
  68.  
  69. static void ExitFailure(const char *, const char *) NORETURN;
  70.  
  71. static void
  72. ExitFailure(const char *cause, const char *insertme)
  73. {
  74.   fprintf(stderr, cause, insertme);
  75.  
  76.   exit(EXIT_FAILURE);
  77. }
  78.  
  79. static void
  80. check(const char *ptr)
  81. {
  82.   if(!*ptr)
  83.   {
  84.     ExitFailure("Unexpected EOL\n", NULL);
  85.   }
  86. }
  87.  
  88. static void warnhim(int linenr, const char *format, ...) gnuspec(__attribute__ ((format (printf, 2, 3))));
  89.  
  90. static void
  91. warnhim(int linenr, const char *format, ...)
  92. {
  93.   char linebuf[250];
  94.   va_list vl;
  95.  
  96.   va_start(vl,format);
  97.   vsprintf(linebuf, format, vl);
  98.   va_end(vl);
  99.  
  100.   fprintf(stderr, "Warning line %d: %s\n", linenr, linebuf);
  101. }
  102.  
  103. static FILE *
  104. OpenLVO(const char *name, const char *outdir, const char *outform)
  105. {
  106.   FILE *lvos;
  107.   char lvoname[MAXLINELEN];
  108.  
  109.   strcpy(lvoname, outdir);
  110.  
  111.   if(name)
  112.   {
  113.     char *k = (char *)name, *p;
  114.     int lvonamlen;
  115.  
  116.     if((p = strrchr(k, '/')) != NULL) k = p + 1;
  117.     if((p = strrchr(k, ':')) != NULL) k = p + 1;
  118.  
  119.     strcat(lvoname, k);
  120.  
  121.     lvonamlen = strlen(lvoname);
  122.  
  123.     if((lvonamlen > 7) && !strcmp(lvoname+lvonamlen-7, "_lib.fd"))
  124.     {
  125.       lvoname[lvonamlen-7] = '\0';
  126.     }
  127.     else if((lvonamlen > 3) && !strcmp(lvoname+lvonamlen-3, ".fd"))
  128.     {
  129.       lvoname[lvonamlen-3] = '\0';
  130.     }
  131.  
  132.     strcat(lvoname, "_lvo.s");
  133.   }
  134.   else
  135.   {
  136.     strcat(lvoname, "fd_lvo.s");
  137.   }
  138.  
  139.   printf(outform, lvoname, lvoname, lvoname);
  140.  
  141.   lvos = fopen(lvoname, "w");
  142.  
  143.   return(lvos);
  144. }
  145.  
  146. static void
  147. ProcessFD(const char *name, int mode, const char *outdir, const char *outform)
  148. {
  149.     FILE *fd, *lvos;
  150.     FILE *out;
  151.     int offset = 0, i, j, count, savecount;
  152.     char function[80], tmpfuncnam[80], ff[MAXLINELEN+8], base[50];
  153.     char line[MAXLINELEN];
  154.     register char *p;
  155.     char *functionp;
  156.     int reg[NUMREGS], loops, linenr = 0;
  157.     BOOL public = -1;           /* Why FALSE? */
  158.  
  159.     /*  "-1" is the initial value for "public". It means:
  160.     **  no statement yet.
  161.     */
  162.  
  163.     *function = *base = *line = '\0';
  164.  
  165.     if(name) fd = fopen(name, "r");
  166.     else     fd = stdin;
  167.  
  168.     if(!fd) ExitFailure("Could not open `%s'\n", name);
  169.  
  170.     setvbuf(fd, NULL, _IOFBF, BUFFEREDLEN);             /* maybe _IOLBF? */
  171.  
  172.     if(!(lvos = OpenLVO(name, outdir, outform)))
  173.       ExitFailure("Could not create lvo file\n", NULL);
  174.  
  175.     setvbuf(lvos, NULL, _IOFBF, BUFFEREDLEN);
  176.  
  177.     for(;;)
  178.     {
  179.         char *k;
  180.  
  181.         if(!fgets(line, MAXLINELEN-1, fd)) ExitFailure("Unexpected EOF\n", NULL);
  182.  
  183.         linenr ++;
  184.  
  185.         if((*line == '*') || !*line) continue;
  186.  
  187.         switch(*line + line[2])
  188.         {
  189.           case ('#'+'b'):
  190.             if(!strncmp(line, "##base", 6))
  191.             {
  192.                 if(*base) warnhim(linenr, "##base detected more than once!");
  193.  
  194.                 p = line+6; while(isspace(*p)) p++;
  195.                 k = base  ; while(isgraph(*p)) *k++ = *p++;
  196.  
  197.                 *k = '\0';
  198.  
  199.                 if(mode & DEBUG) printf("Base set to `%s'\n", base);
  200.                 continue;
  201.             }
  202.  
  203.             if(!strncmp(line, "##bias", 6))
  204.             {
  205.                 p = line+6; while(isspace(*p)) p++;
  206.                 sscanf(p, "%i", &offset);
  207.  
  208.                 if(mode & DEBUG) printf("Bias set to -%d\n", offset);
  209.                 continue;
  210.             }
  211.             break;
  212.  
  213.           case ('#'+'p'):
  214.             if(!strncmp(line, "##public", 8))
  215.             {
  216.                 if(public == TRUE)  warnhim(linenr, "##public after ##public detected!");
  217.                 else                public = TRUE;
  218.  
  219.                 if(mode & DEBUG) printf("Turned on public mode at bias -%d\n", offset);
  220.                 continue;
  221.             }
  222.  
  223.             if(!strncmp(line, "##private", 9))
  224.             {
  225.                 if(public == FALSE) warnhim(linenr, "##private after ##private detected!");
  226.                 else                public = FALSE;
  227.  
  228.                 if(mode & DEBUG) printf("Turned off public mode at bias -%d\n", offset);
  229.                 continue;
  230.             }
  231.             break;
  232.  
  233.           case ('#'+'e'):
  234.             if(!strncmp(line, "##end", 5)) return;
  235.             break;
  236.         }
  237.  
  238.         if(*line == '#')
  239.         {
  240.           warnhim(linenr, "Unknown directive: `%s'!", line);
  241.           continue;
  242.         }
  243.  
  244.         if(!public)
  245.         {
  246.           offset += 6;
  247.           continue;
  248.         }
  249.  
  250.         if(public == -1)
  251.         {
  252.           warnhim(linenr, "Neither ##public nor ##private specified yet. Assuming ##public.");
  253.           public = TRUE;
  254.         }
  255.  
  256.         functionp = function;
  257.  
  258.         for(loops=0; loops<=1; loops++)
  259.         {
  260.             char *p = line; char *k = functionp;
  261.  
  262.             while(isspace(*p)) p++;
  263.  
  264.             if(!loops)
  265.             {
  266.                 while((*p != '(') && *p) *k++ = *p++;
  267.  
  268.                 check(p);
  269.                 *k = '\0';
  270.  
  271.                 fprintf(lvos, "_LVO%s\tequ\t-%d\n"
  272.                               "\txdef\t_LVO%s\n",
  273.                               functionp, offset, functionp
  274.                        );
  275.             }
  276.             else
  277.             {
  278.                 while((*p != '(') && *p) p++;
  279.                 check(p);
  280.             }
  281.  
  282.             if(mode & DEBUG) printf("function=%s, loops=%d\n", functionp, loops);
  283.  
  284.             /* Open function stub source file */
  285.  
  286.             sprintf(ff, "%s%s.s", outdir, functionp);
  287.  
  288.             printf(outform, ff, ff, ff);
  289.  
  290.             out = fopen(ff, "w");
  291.             if(!out) ExitFailure("Could not create <%s>\n", functionp);
  292.             setvbuf(out, NULL, _IOFBF, BUFFEREDLEN);
  293.  
  294.             /* Write assembler headers */
  295.  
  296.             if(mode & SMALLDATA) fprintf(out, "\tnear\t%s,-2\n", regnames[A4]);
  297.             if(mode & SMALLCODE) fputs  (     "\tnear\tcode\n" , out);
  298.  
  299.             if(*base) fprintf(out, "\txref\t%s\n", base);
  300.  
  301.             fprintf(out, "\txdef\t_%s\n"
  302.                          "\tsection\t\"CODE\",code\n"
  303.                          "\n"
  304.                          "_%s:\n",
  305.                          functionp, functionp
  306.                    );
  307.  
  308.             /* Set all registers to 'unused' */
  309.  
  310.             for(i=0; i<NUMREGS; i++) reg[i] = 0;
  311.  
  312.             /* Skip argument names */
  313.  
  314.             while((*p!=')') && *p) p++;
  315.  
  316.             check(p);
  317.             p++;
  318.  
  319.             /* Search for beginning of register list */
  320.  
  321.             while((*p!='(') && *p) p++;
  322.  
  323.             check(p);
  324.             p++;
  325.  
  326.             /* Scan register list */
  327.  
  328.             count = savecount = 0;
  329.  
  330.             while((*p!=')') && *p)
  331.             {
  332.                 /* Check whether register description is valid */
  333.  
  334.                 if((!((*p=='a') || (*p=='A') || (*p=='d') || (*p=='D'))) || !((p[1]>='0') && (p[1]<='7')))
  335.                     ExitFailure("Bad register description\n", NULL);
  336.  
  337.                 /* Convert description to internal enum format */
  338.                 /* Corrected: 'A' was not recognized           */
  339.  
  340.                 if((*p=='a') || (*p=='A')) j = p[1] -  '0';
  341.                 else                       j = p[1] - ('0'-8);
  342.  
  343.                 /* Mark register as used and save its argument counter */
  344.  
  345.                 reg[j] = ++count;
  346.  
  347.                 /* Increase counter if register has to be saved */
  348.  
  349.                 if(!(j==A0 || j==A1 || j==A6 || j==D0 || j==D1))
  350.                   savecount ++;
  351.  
  352.                 /* Search for next register */
  353.  
  354.                 p += 2;
  355.                 while(isspace(*p) && *p)     p++;
  356.  
  357.                 if((*p == '/') || (*p==',')) p++;
  358.                 else if(*p != ')') ExitFailure("Parse error - ')' expected\n", NULL);
  359.  
  360.                 while(isspace(*p) && *p)     p++;
  361.  
  362.                 check(p);
  363.             }
  364.  
  365.             if(savecount)
  366.             {
  367.                 /* 'savecount' registers have to be saved */
  368.  
  369.                 /* Always save library register */
  370.  
  371.                 if((mode & FASTCALL) || (savecount == 1))
  372.                 {
  373.                   /*  Store registers sequential. NEW: Changed that it'll also be
  374.                   **  used if only two (including library register) registers have
  375.                   **  to be stored. That's faster than the original method.
  376.                   */
  377.  
  378.                   fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  379.                 }
  380.                 else
  381.                 {
  382.                   /*  It would be better to set A6 to the end of the list ...
  383.                   */
  384.  
  385.                   fprintf(out, "\tmovem.l\t%s", regnames[A6]);
  386.                 }
  387.  
  388.                 for(i=2; i<NUMREGS; i++)        /* Can start at 2, because 0 and 1 are ignored */
  389.                 {
  390.                     if(reg[i] != 0)
  391.                     {
  392.                       switch(i)
  393.                       {
  394.                         case D0:
  395.                         case D1:
  396.                           break;
  397.  
  398.                         case A6:
  399.                           warnhim(linenr, "Register conflict in `%s' (using libbasereg)!", functionp);
  400.                           break;
  401.  
  402.                         default:
  403.                           if((mode & FASTCALL) || (savecount == 1))
  404.                           {
  405.                             fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[i], regnames[A7]);
  406.                           }
  407.                           else
  408.                           {
  409.                             fprintf(out, "/%s", regnames[i]);
  410.                           }
  411.                           break;
  412.                       }
  413.                     }
  414.                 }
  415.  
  416.                 if(!((mode & FASTCALL) || (savecount == 1))) fprintf(out, ",-(%s)\n", regnames[A7]);
  417.             }
  418.             else
  419.             {
  420.                /*  No registers have to be saved, so just save the register
  421.                **  where the library base will be stored
  422.                */
  423.  
  424.                fprintf(out, "\tmove.l\t%s,-(%s)\n", regnames[A6], regnames[A7]);
  425.             }
  426.  
  427.             /* Load A6 with base NOW, so there's no conflict with SMALLDATA and A4 anymore ... */
  428.  
  429.             if(*base != '\0')
  430.             {
  431.                 if(mode & SMALLDATA)
  432.                 {
  433.                   fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%s,%s),%s\n"
  434.                                                   : "\tmove.l\t%s(%s),%s\n",
  435.                                base, regnames[A4], regnames[A6]
  436.                          );
  437.                 }
  438.                 else
  439.                 {
  440.                   fprintf(out, "\tmove.l\t%s,%s\n", base, regnames[A6]);
  441.                 }
  442.             }
  443.             else ExitFailure("No base defined!\n", NULL);
  444.  
  445.             for(j=1; j<=count; j++)     /* Arguments */
  446.             {
  447.                 for(i=0; i<NUMREGS; i++) /* Registers */
  448.                 {
  449.                     if(reg[i] == j)     /* Argument in THIS register? */
  450.                     {
  451.                         int saveoffset = (savecount+j+1)<<2;
  452.  
  453.                         if((i>=D7) || (reg[i+1] != j+1) || ((loops==1) && (j>=count-1)))
  454.                         {
  455.                             if(!loops || (j<count))
  456.                             {
  457.                                 fprintf(out, (mode & NEWNOTATE) ? "\tmove.l\t(%d,%s),%s\n"
  458.                                                                 : "\tmove.l\t%d(%s),%s\n",
  459.                                               saveoffset, regnames[A7], regnames[i]);
  460.                             }
  461.                             else
  462.                             {
  463.                               if(i <= 7)
  464.                               {
  465.                                 /*  adress register */
  466.  
  467.                                 fprintf(out, (mode & NEWNOTATE) ? "\tlea\t(%d,%s),%s\n"
  468.                                                                 : "\tlea\t%d(%s),%s\n",
  469.                                              saveoffset, regnames[A7], regnames[i]
  470.                                        );
  471.                               }
  472.                               else
  473.                               {
  474.                                 /*  data register  */
  475.  
  476.                                 /*  Changed: moveq.l will be forced if possible
  477.                                 **  (there are still assemblers that do not do this
  478.                                 **  automatically).
  479.                                 */
  480.  
  481.                                 fprintf(out, "\tmove%s\t#%d,%s\n" \
  482.                                              "\tadd.l\t%s,%s\n",
  483.                                              (saveoffset <= 127) ? "q" : ".l",
  484.                                              saveoffset, regnames[i], regnames[A7], regnames[i]
  485.                                        );
  486.                               }
  487.                             }
  488.                         }
  489.                         else
  490.                         {
  491.                             /* Here no fastcall - slower. :-( */
  492.  
  493.                             fprintf(out, (mode & NEWNOTATE) ? "\tmovem.l\t(%d,%s),%s"
  494.                                                             : "\tmovem.l\t%d(%s),%s",
  495.                                          saveoffset, regnames[A7], regnames[i]
  496.                                    );
  497.  
  498.                             while((i<D7) && (reg[i+1] == j+1) && (!loops || (j<count-1)))
  499.                             {
  500.                                 i++; j++;
  501.  
  502.                                 fprintf(out, "/%s", regnames[i]);
  503.                             }
  504.  
  505.                             fputc('\n', out);
  506.                         }
  507.                     } /* if reg[i]==j */
  508.                 } /* for i */
  509.             } /* for j */
  510.  
  511.             /* Now place the real function call */
  512.  
  513.             fprintf(out, (mode & NEWNOTATE) ? "\tjsr\t(-%d,%s)\n"
  514.                                             : "\tjsr\t-%d(%s)\n",
  515.                          offset, regnames[A6]
  516.                    );
  517.  
  518.             /* Start restoring registers ... libbasereg first. */
  519.  
  520.             if(!((mode & FASTCALL) || (savecount == 1)))
  521.             {
  522.               if(!savecount) fprintf(out, "\tmove.l\t(%s)+,%s" , regnames[A7], regnames[A6]);
  523.               else           fprintf(out, "\tmovem.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  524.             }
  525.  
  526.             /* Now the others */
  527.  
  528.             for(i=2; i<NUMREGS; i++)
  529.             {
  530.                 if((mode & FASTCALL) || (savecount == 1))
  531.                 {
  532.                   j = (NUMREGS+1) - i;          /* swap direction; okay for != 16 regs? */
  533.                 }
  534.                 else
  535.                 {
  536.                   j = i;
  537.                 }
  538.  
  539.                 if(reg[j])
  540.                 {
  541.                   switch(j)
  542.                   {
  543.                     case A6:
  544.                     case D0:
  545.                     case D1:
  546.                       break;
  547.  
  548.                     default:
  549.                       if((mode & FASTCALL) || (savecount == 1))
  550.                       {
  551.                         fprintf(out, "\tmove.l\t(%s)+,%s\n", regnames[A7], regnames[j]);
  552.                       }
  553.                       else
  554.                       {
  555.                         fprintf(out, "/%s", regnames[j]);
  556.                       }
  557.                       break;
  558.                   }
  559.                 }
  560.             }
  561.  
  562.             /* If fastcall was used, a6 was put first. So we pop it last. */
  563.  
  564.             if((mode & FASTCALL) || (savecount == 1))
  565.             {
  566.               fprintf(out, "\tmove.l\t(%s)+,%s", regnames[A7], regnames[A6]);
  567.             }
  568.  
  569.             /* Return from subroutine */
  570.  
  571.             fputs("\n" \
  572.                   "\trts\n" \
  573.                   "\n" \
  574.                   "\tend\n",
  575.                   out
  576.                  );
  577.  
  578.             fclose(out);
  579.  
  580.             if(loops != 0) break;
  581.  
  582.             p = (char *) *varargs;
  583.             loops = 3;
  584.  
  585.             if(mode & DEBUG) printf("Searching function `%s' in vargs table...\n", functionp);
  586.  
  587.             if(p != NULL)
  588.             {
  589.               if(mode & VARGSLOGIC)
  590.               {
  591.                 int fnlen = strlen(functionp);
  592.  
  593.                 if((fnlen > 7) && (!strcmp(functionp + fnlen - 7, "TagList")))
  594.                 {
  595.                   /*  xxxTagList function found. Make xxxTags of it
  596.                   */
  597.  
  598.                   strncpy(tmpfuncnam, functionp, fnlen - 4);
  599.                   strcpy (tmpfuncnam + fnlen - 4,    "s"  );
  600.  
  601.                   functionp = tmpfuncnam;
  602.                   loops     = 0;
  603.                 }
  604.                 else if((fnlen > 1) && ((functionp[fnlen-1] == 'A') && (functionp[fnlen-2] >= 'a') && (functionp[fnlen-2] <= 'z')))
  605.                 {
  606.                   /*  Not that smart recognition... But you probably
  607.                   **  don't want to have a function CreateDA() varargs,
  608.                   **  want you?
  609.                   **
  610.                   **  Recognized are functions that end with 'A' and that
  611.                   **  have a lowercase letter before that.
  612.                   */
  613.  
  614.                   strcpy(tmpfuncnam, functionp);
  615.                   tmpfuncnam[fnlen-1] = '\0';
  616.  
  617.                   functionp = tmpfuncnam;
  618.                   loops     = 0;
  619.                 }
  620.  
  621.                 if(!loops)
  622.                 {
  623.                   if(mode & DEBUG) puts("Found via internal logic!");
  624.                 }
  625.               }
  626.  
  627.               if(loops) for(i=0; p != NULL; i+=2)
  628.               {
  629.                 if(!strcmp(p, functionp))
  630.                 {
  631.                     if(mode & DEBUG) puts("Found!");
  632.  
  633.                     functionp = (char *) varargs[i - 1];        /* [i+1] */
  634.                     loops = 0;
  635.                     break;
  636.                 }
  637.  
  638.                 /*i += 2;*/
  639.                 p = (char *) varargs[i];
  640.               }
  641.             }
  642.         }
  643.  
  644.         offset += 6;
  645.     } /* for(;;) */
  646.  
  647.     if(name) fclose(fd);
  648.  
  649.     fputs("\n\tend\n", lvos);
  650.  
  651.     fclose(lvos);
  652. }
  653.  
  654. /*  Append '/' to path if needed
  655. */
  656.  
  657. static void
  658. fillpath(char *dirpath)
  659. {
  660.   int sl = strlen(dirpath);
  661.  
  662.   switch(dirpath[sl-1])
  663.   {
  664.     case ':':   /* ':' should be AMIGA-only! This will be commented out. */
  665.     case '/':
  666.       break;
  667.  
  668.     default:
  669.       strcpy(dirpath+sl, "/");
  670.       break;
  671.   }
  672. }
  673.  
  674. /*  Show program usage
  675. */
  676.  
  677. static void Usage(const char *) NORETURN;
  678.  
  679. static void
  680. Usage(const char *myname)
  681. {
  682.   printf("fd2lib 1.3  (c) 9/96 by Volker Barthelmann / Johnny Teveßen\n"
  683.          "\n"
  684.          "  -- Caution: Needs ~5000 byte stack! --\n"
  685.          "\n"
  686.          "Usage : %s [-sc] [-sd] [-40] [-on] [-nv] [-o <dir>] [-of <format>]\n"
  687.          "           [-d] [-?|--help] [files/pattern]\n"
  688.          "\n"
  689.          "  -sc : Use small code model (else large code model)\n"
  690.          "  -sd : Use small data model (else large data model)\n"
  691.          "  -40 : Use fast call model for 68040\'s (no 'movem's)\n"
  692.          "  -on : Use old motorola assembler notation\n"
  693.          "  -nv : No varargs logic - ...A and ...TagList will not be detected\n"
  694.          "  -o  : Specify directory to store source files in\n"
  695.          "  -of : C printf style output format to generate compiling\n"
  696.          "        script. Three `%%s' are replaced with output file name\n"
  697.          "  -d  : Turn on debugging/verbose mode\n"
  698.          "  -?  : Show help/version and quit\n"
  699.          "files : FD files to convert, defaults to stdin\n"
  700.          "\n"
  701.          "Commandline is parsed left-to-right. Specifying\n"
  702.          "\"alib_lib.fd -sd blib_lib.fd\" will result in alib\n"
  703.          "getting large data model.\n",
  704.          myname
  705.         );
  706.  
  707.   exit(0);
  708. }
  709.  
  710. /*  Remember: ixemul.library does command line expansion, eg.:
  711. **
  712. **  redrose# fd2lib -sc -sd /fd/a*_lib.fd
  713. **
  714. **  will become:
  715. **
  716. **  redrose# fd2lib -sc -sd /fd/amigaguide_lib.fd /fd/asl_lib.fd ...
  717. **
  718. */
  719.  
  720. int
  721. main(int argc, char **argv)
  722. {
  723.     int erg       = 0 /*EXIT_FAILURE*/;
  724.     int mode      = NEWNOTATE | VARGSLOGIC;
  725.     int filesdone = 0;
  726.  
  727.     char outdir[80] = "", outform[250] = "";
  728.  
  729.     if(argc > 1)
  730.     {
  731.       int i;
  732.  
  733.       for(i=1; i<argc; i++)
  734.       {
  735.         if(argv[i][0] == '-')
  736.         {
  737.           /* Parse option */
  738.  
  739.                if( !strcmp(argv[i], "-sc")) mode |=  SMALLCODE;
  740.           else if( !strcmp(argv[i], "-sd")) mode |=  SMALLDATA;
  741.           else if( !strcmp(argv[i], "-40")) mode |=  FASTCALL;
  742.           else if( !strcmp(argv[i], "-on")) mode &= ~NEWNOTATE;
  743.           else if( !strcmp(argv[i], "-nv")) mode &= ~VARGSLOGIC;
  744.           else if( !strcmp(argv[i], "-o" ))
  745.           {
  746.             if(i < (argc-1))
  747.             {
  748.               i ++;
  749.  
  750.               if(strlen(argv[i]) < sizeof(outdir))
  751.               {
  752.                 strcpy  (outdir, argv[i]);
  753.                 fillpath(outdir);
  754.               }
  755.               else
  756.               {
  757.                 fprintf(stderr, "Path too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outdir));
  758.               }
  759.             }
  760.             else
  761.             {
  762.               fputs("No path specified after `-o'!\n", stderr);
  763.             }
  764.           }
  765.           else if( !strcmp(argv[i], "-of"))
  766.           {
  767.             if(i < (argc-1))
  768.             {
  769.               i ++;
  770.  
  771.               if(strlen(argv[i]) < sizeof(outform))
  772.               {
  773.                 strcpy(outform, argv[i]);
  774.                 strcat(outform, "\n"   );
  775.               }
  776.               else
  777.               {
  778.                 fprintf(stderr, "Format too long. Maximum is %lu characters. Ignored.\n", (unsigned long)sizeof(outform));
  779.               }
  780.             }
  781.             else
  782.             {
  783.               fputs("No format specified after `-of'!\n", stderr);
  784.             }
  785.           }
  786.           else if( !strcmp(argv[i], "-d" )) mode |=  DEBUG;
  787.           else if((!strcmp(argv[i], "-?" )) ||
  788.                   (!strcmp(argv[i], "--help"))) Usage(*argv);
  789.           else
  790.           {
  791.             fprintf(stderr, "Unknown option `%s'\n\n", argv[i]);
  792.             Usage(*argv);
  793.           }
  794.         }
  795.         else
  796.         {
  797.           /* Process file */
  798.  
  799.           if(argv[i][0] == '?') Usage(*argv);
  800.           else
  801.           {
  802.             ProcessFD(argv[i], mode, outdir, outform);
  803.             filesdone ++;
  804.           }
  805.         }
  806.       }
  807.     }
  808.  
  809.     if(!filesdone) ProcessFD(NULL, mode, outdir, outform);
  810.  
  811.     return(erg);
  812. }
  813.